package com.blockchainenergy.common;

import com.blockchainenergy.blockChain.DataChain;
import com.blockchainenergy.blockChain.KeyChainCluster;

import java.util.Random;

public class Encryption {
    private static DataChain dataChain;
    private static KeyChainCluster keyChainCluster;

    static {
        try {
            dataChain = DataChain.getInstance();
            keyChainCluster = KeyChainCluster.getInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 加密
     *
     * @param date 加密数据
     */
    public static void encryption(long data) {
        // 随机生成一段长度为10的01字符串
        int r = new Random().nextInt(1 << 10);
        String key = Integer.toBinaryString(r);
        long keyL = Long.parseLong(key);
        // 加密数据打包成区块上数据链
        dataChain.addBlock(keyL + data);
        // n个节点中随机生成5个 节点编号：1，2，3，4，5..
        int n = keyChainCluster.getNodeNum();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = i;
        }
        int[] nodes = selectM(n, 5);
        // 发送字符给节点
        sendStringToNodes(nodes, key);
        // 每个节点上传到自己的密钥链
        keyChainCluster.addBlockEveryKeyNode();
    }

    /**
     * 解密
     *
     * @param date 待解密数据
     * @param x    数据在数据链上的位置
     * @return 原始数据
     * @throws Exception
     */
    public static long decryption(long data, int x) throws Exception {
        int n = keyChainCluster.getNodeNum();
        char[][] res = keyChainCluster.getXKey(x);
        StringBuilder sb = new StringBuilder();
        for (int j = 0; j < 10; j++) {
            int num1 = 0, num0 = 0;
            for (int i = 1; i <= n; i++) {
                if (res[i][j] == '1') num1++;
                else if (res[i][j] == '2') num0++;
            }
            if (num1 == num0) throw new Exception("数据被篡改");
            sb.append(num1 > num0 ? 1 : 0);
        }
        return data - Long.parseLong(sb.toString());
    }

    private static boolean sendStringToNodes(int[] nodes, String key) {
        char[] cs = key.toCharArray();
        int[][] combination = new int[][]{{1, 2, 3}, {1, 2, 4}, {1, 2, 5}, {1, 3, 4}, {1, 3, 5}, {1, 4, 5}, {2, 3, 4}, {2, 3, 5}, {2, 4, 5}, {3, 4, 5}};
        for (int i = 0; i < 10; i++) {
            for (int c : combination[i]) {
                // 发送数据给节点 节点接收之后更新自己的char[]
                keyChainCluster.sendStringToNode(nodes[c], cs[i], i);// 节点编号 发送的字符 字符下标
            }
        }
        return true;
    }

    // n 中随机选5个数
    private static int[] selectM(int n, int m) {
        int[] res = new int[m + 1];
        int[] a = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            a[i] = i;
        }
        for (int i = 1; i <= m; i++) {
            int r = n - new Random().nextInt(n + 1 - i);// [1~n] [2~n]
            swap(a, r, i);
            res[i] = a[i];
        }
        return res;
    }

    private static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }

    public static void main(String[] args) throws Exception {
        long toEncryption = 0l;
        long toDecryption = 0l;
        encryption(toEncryption);
        decryption(toDecryption,0);
    }
}
